//
//  Coordinator.m
//  LockTest
//
//  Created by ZhangBo on 2018/12/2.
//  Copyright © 2018 ZhangBo. All rights reserved.
//

#import "Coordinator.h"

#pragma mark -- 生产者

@implementation Producer

- (instancetype)initWithConditon:(NSCondition *)condition collector:(NSMutableArray *)collector {

    /*  生产者的初始化器用于协调配合的 NSCondition对象和用于存放产品的 collector。
     *  初始状态设置为不要生产（_shouldProduct = false）
     *  */

    self = [super init];
    if (self) {
        self.condition = condition;
        self.collector = collector;
        self.shouldProduce = NO;
        self.itemName = @"";
    }
    return self;
}

- (void)produce {
    //  生产者会在_shouldProduct 为YES时进行生产。
    //  其他线程需要将其设置为NO以停止生产者的生产

    self.shouldProduce = YES;
    while (self.shouldProduce) {
        //  获得 condition的锁 ，进入临界区
        [self.condition lock];

        //  如果collector 中有未消费的产品，则等待，
        //  这会阻塞当前线程的执行直到condition 被通知signal为止
        if (self.collector.count > 0) {
            [self.condition wait];
        }
        //  将生产的 产品送入collector以供消费
        [self.collector addObject:@"iPhone"];
        NSLog(@"生产:iPhone");
        //  通知其他等待的线程（如果存在）。
        //  这里是产品完成生产的标志，并将产品加入到collector，可供消费
        [self.condition signal];
        //  释放锁
        [self.condition unlock];
        [NSThread sleepForTimeInterval:2];
    }
}

@end

#pragma mark -- 消费者

@implementation Consumer

- (instancetype)initWithConditon:(NSCondition *)condition collector:(NSMutableArray *)collector {
    /*  消费者的初始化器用于协调配合的 NSCondition对象和用于存放产品的collector。
     *  初始状态设置为不消费（_shouldConsumer = false）
     */
    self = [super init];
    if (self) {
        self.condition = condition;
        self.collector = collector;
        self.shouldConsumer = NO;
        self.itemName = @"";
    }
    return self;
}

- (void)consumer {
    //  消费者会在_shouldConsumer 为YES时 消费者会进行消费。
    //  其他线程需要将其设置为NO来停止消费者的消费

    self.shouldConsumer = YES;
    while (self.shouldConsumer) {
        //获得 condition的锁 ，进入临界区
        [self.condition lock];

        // 如果collector中没有产品，则等待，
        // 这会阻塞当前线程的执行直到condition被通知signal为止
        if (self.collector.count == 0) {
            [self.condition wait];
        }

        NSString *item = self.collector[0];
        NSLog(@"买入:%@", item);
        //消费collector 中的产品。确保已经从collector 中移除它
        [self.collector removeObjectAtIndex:0];
        //通知其他等待的线程（如果存在）。这里标识一个产品被消费并从collector 中移除了
        [self.condition signal];
        //释放锁
        [self.condition unlock];
    }
}

@end

#pragma mark -- 测试类

@implementation Coordinator

- (void)start {

    //  Coordinator 类为生产者和消费者准备好了输入数据（具体指的是condition和collector）
    NSMutableArray *pipeline = [NSMutableArray array];
    NSCondition *conditon = [NSCondition new];

    Producer *p = [[Producer alloc] initWithConditon:conditon collector:pipeline];
    Consumer *c = [[Consumer alloc] initWithConditon:conditon collector:pipeline];

    //  在不同的线程中开启生产和消费任务
    [NSThread detachNewThreadSelector:@selector(startProduct:) toTarget:self withObject:p];
    [NSThread detachNewThreadSelector:@selector(startConsumer:) toTarget:self withObject:c];

    //  一旦完成，分别设置生产者和消费者停止生产和消费
    p.shouldProduce = NO;
    c.shouldConsumer = NO;
    //  因为生产者和消费者线程可能会等待，所以broadcast本质上会通知所有等待中的线程。
    //  不同的是，signal 方法 只会影响一个等待的线程
    [conditon broadcast];

}

- (void)startProduct:(id)sender {
    //开始生产
    Producer *p = sender;
    [p produce];
}

- (void)startConsumer:(id)sender {
    //开始消费
    Consumer *c = sender;
    [c consumer];
}

@end
